Network Load Balancer (NLB) のソースIPアドレスに思いを馳せてみた
Network Load Balancerのターゲットに設定するセキュリティグループルールに悩む
こんにちは、のんピ(@non____97)です。
皆さんはNetwork Load Balancer(以降、NLB)のターゲットに設定するセキュリティグループルールに悩んだことはありますか? 私は悩んでいます。
NLBにはセキュリティグループが設定できません。そのため、ALBを使うときのように、ターゲットに設定するセキュリティグループルールでALBがアタッチしているセキュリティグループからのアクセスを許可するみたいなこともできません。
ということで、今回はNLBを使用する場合にターゲットに設定するセキュリティグループで、どのようなIPアドレスからのアクセスを許可すれば良いか確認してみます。
いきなりまとめ
ターゲットタイプ | クライアントIPアドレスの保持 | Nginxのログに記録されたIPアドレス |
---|---|---|
インスタンス | 無効 | NLBのIPアドレス |
インスタンス | 有効 | VPCエンドポイントを使わない場合 : クライアントのIPアドレス VPCエンドポイントを使う場合 : NLBのIPアドレス |
IPアドレス | 無効 | NLBのIPアドレス |
IPアドレス | 有効 | VPCエンドポイントを使わない場合 : クライアントのIPアドレス VPCエンドポイントを使う場合 : NLBのIPアドレス |
ALB | 有効 | ALBのIPアドレス |
- エンドのターゲットのセキュリティグループルールでは上述のIPアドレスからのアクセスを許可すれば良い
- クライアントIPアドレスの保持を無効にした場合は、ターゲットのセキュリティグループでNLBのIPアドレスのみに通信を制御したとしても、効果は薄い
- PrivateLinkを使用することで異なるVPCからNLBへの送信元は制御できる
- どうしても同じVPC内の通信を制御したい場合はNetwork ACLを使用する
- 個人的には運用が辛くなる予感がするのでおすすめしない
- 実はAWS公式ドキュメントでNLBを使用する際のセキュリティグループやNetwork ACLの推奨ルールが公開されている
AWS公式ドキュメントを眺めてみる
まず、AWS公式ドキュメントをニヤニヤしながら眺めてみます。
ターゲットグループではクライアントIPアドレスの保持をするか選択することができます。
クライアントIPアドレスの保持を有効にした場合は、ターゲットが受信するトラフィックのIPアドレスは、アクセス元クライアントのIPアドレスになります。
一方、クライアントIPアドレスの保持を無効にした場合、ターゲットが受信するトラフィックのIPアドレスはNLBのENIに割り当てられているプライベートIPアドレスになります。
そのため、クライアントIPアドレスの保持が有効なのか無効なのかでセキュリティグループルールで許可するIPアドレスを変更する必要がありそうですね。
なお、ターゲットグループのプロトコルがUDPとTCP_UDPの場合は、クライアントIPアドレスの保持を無効にすることはできません。
また、いくつか注意事項があります。
- クライアントIPアドレスの保持が有効な場合、ターゲットはNLBと同じVPCにある必要があり、トラフィックはNLBからターゲットに直接フローする必要がある
- ターゲットがNLBと同じVPCにあっても、トラフィックがGateway Load Balancerエンドポイントを介してルーティングされる場合、クライアントIPアドレスの保持はサポートされない
- インスタンスタイプが C1、CC1、CC2、CG1、CG2、CR1、G1、G2、HI1、HS1、M1、M2、M3、T1である場合、クライアントIPアドレスの保持をサポートしない
- クライアントIPアドレスの保持は、AWS PrivateLinkのトラフィックには影響しない
- AWS PrivateLinkのトラフィックの送信元IPアドレスは、常にNLBのプライベートIPアドレス
- クライアントIPアドレスの保持は、IPv6 から IPv4 に変換されたトラフィックには影響しない
- IPv6 から IPv4 に変換されたトラフィックの送信元IPアドレスは、常にNLBのプライベートIPアドレス
- ターゲットにALBを指定した場合、すべての着信トラフィックのクライアントIPアドレスがNLBによって保存され、ALBに送信される。ALBはターゲットに送信する際にクライアントのIPアドレスを
X-Forwarded-For
ヘッダーに追加する。 - クライアントIPアドレスの保持の変更の反映は新規TCPコネクションから行われる。
- クライアントIPアドレスの保持が有効な場合、ターゲットで確認されたソケットの再利用に関連する TCP/IP 接続の制限が発生することがある
- 接続制限が発生する可能性があるのは、クライアント、またはクライアントの前面にあるNATデバイスが複数のロードバランサーノードに同時に接続する際に、同じ送信元IPアドレスと送信元ポートを使用する場合
- ロードバランサーが同じターゲットにルーティングする場合、接続は同じ送信元ソケットからの接続のようにターゲットに表示され、それにより接続エラーが発生する
- クライアントは再試行 (接続が失敗した場合)、または再接続 (接続が中断した場合)することができる
- 接続エラーは、クライアントIPアドレスの保持を無効にするか、クロスゾーン負荷分散を無効にすることで防止できる
- 接続エラーは、送信元の一時ポートの数を増やすか、ロードバランサーのターゲット数を増やすことによって減らすことができる
- NLBは一意の各ターゲット (IPアドレスとポート) に対して 55,000 の同時接続または 1分あたり約55,000の接続をサポートする
- 接続数を超えた場合は、ポート割り当てエラーが発生する可能性が高くなり、新しい接続を確立できなくなることがある
- ポート割り当てエラーは、
PortAllocationErrorCount
メトリクスを使用して追跡できる - ポート割り当てエラーを修正するには、ターゲットグループにさらに多くのターゲットを追加する
クライアントIPアドレスの保持を有効にすると上手く通信できないみたいな場面に遭遇した際は、上述の注意事項に該当していないか確認すると良さそうですね。
検証してみる
検証方法の整理
手を一切動かさずに「完全に理解した」となるものアレなので、検証してみます。
検証の構成は以下の通りです。
検証は以下5パターンで行います。
- ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を無効
- ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を有効
- ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を無効
- ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を有効
- ターゲットをALB かつ クライアントIPアドレスの保持を有効
ターゲットタイプがALBの場合、クライアントIPアドレスの保持は有効で固定なので、無効のパターンは検証しません。
そして、各パターン毎に以下6通りのアクセス方法を試してみます。
- Consumer EC2 on Provider VPCからNLBにアクセス
- Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス
- Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス
- Consumer EC2 on Consumer VPCからNLBにアクセス
- Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス
- Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス
確認する観点は、Provider EC2 Instance上で稼働しているNginxのログ(/var/log/nginx/access.log
)にどのようなIPアドレスが記録されるかです。
各リソースのIPアドレスもしくはDNS名は以下の通りです。
リソース | IPアドレス or DNS名 |
---|---|
Consumer EC2 on Provider VPC Instance IP Address | 10.10.0.8 |
Consumer EC2 on Consumer VPC Instance IP Address | 10.11.0.14 |
Provider EC2 Instance IP Address | 10.10.0.5 |
NLB IP Address | 10.10.0.39, 10.10.0.60 |
ALB IP Address | 10.10.0.36, 10.10.0.57 |
VPC Endpoint on Provider VPC IP Address | 10.10.0.42, 10.10.0.62 |
VPC Endpoint on Consumer VPC IP Address | 10.11.0.41, 10.11.0.54 |
NLB DNS Name | NlbSt-NLB55-7WA9M9TJ833-35a3ce57527445c6.elb.us-east-1.amazonaws.com |
ALB DNS Name | internal-NlbSt-ALBAE-1PN13OCA7BSKP-1952647894.us-east-1.elb.amazonaws.com |
VPC Endpoint on Provider VPC DNS Name | vpce-05be3c9642de86b54-56xh4yfc.vpce-svc-0da2f1652e4c771cb.us-east-1.vpce.amazonaws.com |
VPC Endpoint on Consumer VPC DNS Name | vpce-059c0ebcdefe5b45b-ro5i47u9.vpce-svc-0da2f1652e4c771cb.us-east-1.vpce.amazonaws.com |
また、検証の構成は全てAWS CDKで定義しました。使用したコードは以下リポジトリに保存しています。
ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を無効
それでは、「ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を無効」のパターンから試してみます。
各アクセス方法毎のログは以下の通りです。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 10.10.0.39 - - [10/Jun/2022:06:45:27 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:06:45:42 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:06:45:51 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 10.10.0.39 - - [10/Jun/2022:06:46:29 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:06:46:39 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:06:46:50 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-"
全てNLBのIPアドレスである10.10.0.39
が記録されていますね。
「ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を無効」で構成する場合、ターゲットに設定するセキュリティグループルールでは、NLBのIPアドレスからのアクセスを許可する必要があると判断できます。
ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を有効
次に「ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を有効」のパターンです。
各アクセス方法毎のログは以下の通りです。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 10.10.0.8 - - [10/Jun/2022:07:18:13 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:18:38 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:18:48 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 10.11.0.14 - - [10/Jun/2022:07:19:04 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:19:15 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:19:30 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-"
NLBに直接アクセスした場合はアクセス元のEC2インスタンスのIPアドレスが記録されています。また、VPCエンドポイント経由でアクセスした場合はNLBのIPアドレスが記録されています。
「ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を有効」で構成する場合、以下のようにVPCエンドポイントを使うかどうかでターゲットに設定するセキュリティグループルールが変化しそうです。
- VPCエンドポイントを使わない場合 : クライアントのIPアドレスからのアクセスを許可する
- VPCエンドポイントを使う場合 : NLBのIPアドレスからのアクセスを許可する
ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を無効
次に「ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を無効」のパターンです。
各アクセス方法毎のログは以下の通りです。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 10.10.0.39 - - [10/Jun/2022:07:28:34 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:28:47 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:28:56 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 10.10.0.39 - - [10/Jun/2022:07:29:37 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:29:56 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:30:06 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-"
全てNLBのIPアドレスである10.10.0.39
が記録されました。
ターゲットタイプがインスタンスでもIPアドレスでも結果は変わらないようです。
「ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を無効」で構成する場合、ターゲットに設定するセキュリティグループルールでは、NLBのIPアドレスからのアクセスを許可する必要があると判断できます。
ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を有効
次に「ターゲットをProvider EC2 InstanceのIPアドレス かつ クライアントIPアドレスの保持を有効」のパターンです。
各アクセス方法毎のログは以下の通りです。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 10.10.0.8 - - [10/Jun/2022:07:36:33 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:36:45 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:36:56 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 10.11.0.14 - - [10/Jun/2022:07:37:17 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:37:27 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:07:37:37 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-"
こちらもターゲットタイプがインスタンスでもIPアドレスでも結果は変わらず、NLBに直接アクセスした場合はアクセス元のEC2インスタンスのIPアドレスが記録されています。また、VPCエンドポイント経由でアクセスした場合もターゲットタイプがインスタンスの時と同様にNLBのIPアドレスが記録されています。
そのため、「ターゲットをProvider EC2 Instance かつ クライアントIPアドレスの保持を有効」で構成する場合、以下のようにVPCエンドポイントを使うかどうかでターゲットに設定するセキュリティグループルールが変化します。
- VPCエンドポイントを使わない場合 : クライアントのIPアドレスからのアクセスを許可する
- VPCエンドポイントを使う場合 : NLBのIPアドレスからのアクセスを許可する
ターゲットをALB かつ クライアントIPアドレスの保持を有効
最後に「ターゲットをALB かつ クライアントIPアドレスの保持を有効」のパターンです。
まず、AWS公式ドキュメントではクライアントIPアドレスをX-Forwarded-For
ヘッダーに追加すると記載されているので、ログにX-Forwarded-For
の内容が記録されるように設定されているか確認してみます。
Nginxの設定でログフォーマットを確認したところ、末尾に$http_x_forwarded_for
があることから記録されそうですね。
$ cat /etc/nginx/nginx.conf # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 4096; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80; listen [::]:80; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2; # listen [::]:443 ssl http2; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers PROFILE=SYSTEM; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # error_page 404 /404.html; # location = /40x.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } }
各アクセス方法毎のログは以下の通りです。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 10.10.0.36 - - [10/Jun/2022:07:49:12 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.8" or 10.10.0.57 - - [10/Jun/2022:07:50:32 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.8" # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.57 - - [10/Jun/2022:07:50:47 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.60" or 10.10.0.36 - - [10/Jun/2022:07:50:59 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.39" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.36 - - [10/Jun/2022:07:51:21 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.39" or 10.10.0.57 - - [10/Jun/2022:07:51:44 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.60" # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 10.10.0.36 - - [10/Jun/2022:07:52:07 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.11.0.14" or 10.10.0.57 - - [10/Jun/2022:07:52:20 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.11.0.14" # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.36 - - [10/Jun/2022:07:52:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.39" or 10.10.0.57 - - [10/Jun/2022:07:53:02 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.60" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 10.10.0.36 - - [10/Jun/2022:07:53:13 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.39" or 10.10.0.57 - - [10/Jun/2022:07:53:15 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "10.10.0.60"
いずれもALBのIPアドレスが記録されています。ALBはクロスゾーン負荷分散が常に有効になっているため、アクセスによってIPアドレス記録されるIPアドレスが変化しました。
X-Forwarded-For
の箇所に記録されているIPアドレスは以下のように異なります。
- VPCエンドポイントを使わない場合 : クライアントのIPアドレス
- VPCエンドポイントを使う場合 : ALBと同じAZのNLBのIPアドレス
ALBのターゲットのインスタンスに設定するセキュリティグループルールでは、以下のどちらかを設定すれば良さそうです。
- ALBがアタッチしているセキュリティグループからのアクセスを許可する
- ALBのIPアドレスからのアクセスを許可する
- ただし、ALBのIPアドレスはスケールアウトなどのタイミングで変化するため、実際はALBのサブネットのCIDRを許可することになる
また、VPCエンドポイントを使うかどうかでX-Forwarded-For
ヘッダーに追加されるIPアドレスが変わるので、ALBに設定するセキュリティグループルールは以下のように設定する必要があると考えます。
- VPCエンドポイントを使わない場合 : クライアントのIPアドレスからのアクセスを許可する
- VPCエンドポイントを使う場合 : NLBのIPアドレスからのアクセスを許可する
検証のまとめ
Nginxで記録されたIPアドレスをまとめると以下のようになります。
ターゲットタイプ | クライアントIPアドレスの保持 | Nginxのログに記録されたIPアドレス |
---|---|---|
インスタンス | 無効 | NLBのIPアドレス |
インスタンス | 有効 | VPCエンドポイントを使わない場合 : クライアントのIPアドレス VPCエンドポイントを使う場合 : NLBのIPアドレス |
IPアドレス | 無効 | NLBのIPアドレス |
IPアドレス | 有効 | VPCエンドポイントを使わない場合 : クライアントのIPアドレス VPCエンドポイントを使う場合 : NLBのIPアドレス |
ALB | 有効 | ALBのIPアドレス |
エンドのターゲットのセキュリティグループルールでは上述のIPアドレスからのアクセスを許可すれば良いことが分かります。
注意すべき点としては、クライアントIPアドレスの保持を無効にした場合は、ターゲットのセキュリティグループでNLBのIPアドレスのみに通信を制御したとしても、効果は薄いという点です。
上述した通り、NLBにはセキュリティグループを設定することができません。そのため、ターゲットのセキュリティグループでNLBのIPアドレスのみに通信を制御したとしても、NLB側で通信を制限できず、NLBに来た通信は全てターゲットに転送されてしまうので、思っているほどの効果は望めません。
図にするとイメージしやすいかと思います。
回避策はPrivateLinkの使用することです。
PrivateLinkとしてNLBのVPCエンドポイントを作成します。別のVPCからNLBにアクセスする際は、VPCピアリング経由でNLBにアクセスするのではなく、作成したVPCエンドポイントにアクセスします。
VPCエンドポイントはセキュリティグループの割り当てができるので、送信元を制限することができます。
しかし、この図を見て気づいてしまった人はいるでしょう。
「同じVPCだったらどうやって通信制限するんだ」
と
はい、VPCエンドポイントを使っても同じVPC内の通信はセキュリティグループでは制御できません。
セキュリティグループでは制御できません。
「セキュリティグループでは制御できません。」
「「セキュリティグループでは制御できません。」」
「「セ キ ュ リ テ ィ グ ル ー プ で は 制 御 で き ま せ ん 。」」
なので、どうしても同じVPC内の通信を制御したい場合はNetwork ACLを使用します。
NLB専用のサブネットを作成し、作成したサブネットにNetwork ACLを割り当てます。
Network ACLでは同一サブネット内の通信は制御できないので、NLB宛の通信を制限したい場合はNLB専用のサブネットを用意する必要があります。
Network ACLによって、許可されたIPアドレス以外からの通信はNLBに到達することができません。
Network ACLを設定する際の注意点は、少なくともインバウンドルールでNLBのターゲットのIPアドレスを許可する必要がある点です。
Network ACLはステートレスに動作します。仮にインバウンドルールを以下のように全て拒否するようにしてしまうと、どこから通信しようとしてもNLBとターゲットの間でTCPの接続を確立する際のSYN-ACK
で拒否されてしまいます。
// TCPフラグのビットマスク値が "2" である SYN の通信は ACCEPT 5 <AWSアカウントID> eni-022f7e1a5044a88ef 10.10.0.39 10.10.0.5 21136 80 6 2 120 1654854595 1654854615 ACCEPT OK vpc-05d3c75ddee8514e4 subnet-0277111b0b3ce6920 - 2 IPv4 10.10.0.39 10.10.0.5 us-east-1 use1-az6 - - - - egress 1 // TCPフラグのビットマスク値が "18" である SYN-ACK の通信は REJECT 5 <AWSアカウントID> eni-022f7e1a5044a88ef 10.10.0.5 10.10.0.39 80 21136 6 8 480 1654854595 1654854615 REJECT OK vpc-05d3c75ddee8514e4 subnet-0277111b0b3ce6920 - 18 IPv4 10.10.0.5 10.10.0.39 us-east-1 use1-az6 - - - - ingress -
以下のようにインバウンドルールでNLBのターゲットのIPアドレスを許可して再チャレンジしてみます。
# 1. Consumer EC2 on Provider VPCからNLBにアクセス 通信できない # 2. Consumer EC2 on Provider VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:10:11:11 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 3. Consumer EC2 on Provider VPCからProvider VPC上のVPCエンドポイントにアクセス 通信できない # 4. Consumer EC2 on Consumer VPCからNLBにアクセス 通信できない # 5. Consumer EC2 on Consumer VPCからConsumer VPC上のVPCエンドポイントにアクセス 10.10.0.39 - - [10/Jun/2022:10:14:33 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-" # 6. Consumer EC2 on Consumer VPCからProvider VPC上のVPCエンドポイントにアクセス 通信できない
Consumer VPC上のVPCエンドポイントにアクセスするパターンしか通信できなくなりました。
NLBのENIのVPC Flow Logsを確認すると、SYN
だけでなく、SYN-ACK
、FIN
の通信が拒否されなかったことが分かります。
// TCPフラグのビットマスク値が "19" である SYN-ACK と FIN の通信は ACCEPT 5 <AWSアカウントID> eni-022f7e1a5044a88ef 10.10.0.5 10.10.0.39 80 30834 6 3 164 1654855822 1654855824 ACCEPT OK vpc-05d3c75ddee8514e4 subnet-0277111b0b3ce6920 - 19 IPv4 10.10.0.5 10.10.0.39 us-east-1 use1-az6 - - - - ingress - // TCPフラグのビットマスク値が "3" である SYN と FIN の通信は ACCEPT 5 <AWSアカウントID> eni-022f7e1a5044a88ef 10.10.0.39 10.10.0.5 30834 80 6 4 216 1654855822 1654855824 ACCEPT OK vpc-05d3c75ddee8514e4 subnet-0277111b0b3ce6920 - 3 IPv4 10.10.0.39 10.10.0.5 us-east-1 use1-az6 - - - - egress 1
できらぁ!
と検証しておきながら、Network ACLを使用する手法は個人的には運用が辛くなる予感がするのでおすすめしません。
バックエンドのIPアドレスが変わる度にNetwork ACLのインバウンドルールをメンテナンスするのは想像しただけでも大変そうです。
NLBへの通信を本気で制限しようとすると結構大変
NLBのソースIPアドレスに思いを馳せてみました。
NLBへの通信を本気で制限しようとすると結構大変ということが分かりました。
なお、実はAWS公式ドキュメントでセキュリティグループやNetwork ACLの推奨ルールが公開されています。
ここまで検証しなくても良かった気がしますが、それも良いでしょう。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!